iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
AI Engineering

AI Reliability Lab:30 天用 Python 把「AI 好像很準」變成可以量的工程指標系列 第 7

Day 7|AI 說自己有 95% 把握,我真的該信嗎?第一次把 Confidence 拿去校準

  • 分享至 

  • xImage
  •  

前幾天一路做到現在,我其實已經量了不少「可靠性」。

Day 1 先從最基本的 Accuracy 開始,Day 2 看同一題問多次會不會亂飄,Day 3 把 Accuracy 和 Consistency 放在一起,Day 4 開始要求輸出格式真的能進系統,Day 5 加入「不知道就不要亂答」的 Abstention,Day 6 再往前一步,用 confidence threshold 畫出 Risk-Coverage 的關係。

做到 Day 6 時,我原本直覺上會覺得:

既然 confidence 越高的答案通常越值得留下,那是不是代表 confidence 本身就可以相信?

但仔細想,其實完全不是同一件事。

一個模型可以很會「排序」哪些答案比較可靠,卻還是可能把自己的信心喊得太高。

例如它說:

這題我有 95% 把握。

真正的問題不是這個數字看起來高不高,而是:

如果它說了很多次 95%,這些答案真的大約有 95% 是對的嗎?

這就是今天要處理的問題:

Calibration,校準。


Accuracy 一樣,不代表 Confidence 一樣可信

今天我刻意沒有直接接真正的 LLM API。

原因不是做不到,而是如果一開始就丟進真實模型,錯誤可能同時來自 prompt、資料集、模型本身、confidence 產生方式、評分器,最後很難知道我寫的 calibration evaluator 到底有沒有算對。

所以 Day 7 先做的是一個 controlled synthetic experiment

也就是我自己建構兩組資料,讓它們:

Accuracy 完全一樣,但 confidence 行為故意不一樣。

第一組叫做:

matched_confidence

總共 20 筆。

其中 10 筆 confidence = 0.90,剛好 9 筆答對、1 筆答錯。

另外 10 筆 confidence = 0.60,剛好 6 筆答對、4 筆答錯。

所以整體正確率是:

Accuracy = 15 / 20 = 0.75

平均 confidence 剛好也是:

Mean Confidence
= (10 × 0.90 + 10 × 0.60) / 20
= 0.75

第二組叫做:

overconfident

我刻意保留完全相同的 20 個 correctness labels

也就是答對、答錯的位置都沒有改。

唯一改變的是,全部都讓系統宣稱:

confidence = 0.95

因此它的 Accuracy 還是一樣:

Accuracy = 0.75

但是平均 confidence 變成:

Mean Confidence = 0.95

如果我今天只看 Accuracy,兩個系統完全沒有差別。

都是 75%。

可是第二個系統明明正在非常有自信地高估自己。

這就是為什麼 Accuracy 還不夠。
https://ithelp.ithome.com.tw/upload/images/20260920/20184158AjtpIDaePj.png

第一個指標:Confidence Gap

最簡單的做法,是先比較平均 confidence 和實際 accuracy。

我定義:

Confidence Gap = Mean Confidence - Accuracy

如果是正數,代表整體偏 overconfident。

如果是負數,代表整體偏 underconfident。

在第一組資料裡:

0.75 - 0.75 = 0

第二組則是:

0.95 - 0.75 = 0.20

光這裡其實已經可以看到問題。

但是只看平均值還是太粗。

因為兩組完全不同的 confidence 分布,有可能最後平均值剛好一樣。

所以接下來需要真的把「每筆 confidence 和 correctness 的距離」納入計算。


Brier Score:你的自信,錯的時候要付代價

今天加入的第二個指標是 Brier Score。

對 binary correctness 而言,我使用:

Brier Score
= (1 / N) × Σ (confidence_i - correct_i)^2

其中:

  • confidence_i 是模型對第 i 筆答案的 confidence
  • correct_i 則是答案是否正確
  • 正確記為 1
  • 錯誤記為 0

這個公式有一個我很喜歡的特性:

越有自信地答錯,懲罰越大。

假設 confidence = 0.9,而且真的答對:

(0.9 - 1)^2 = 0.01

但如果一樣喊 0.9,結果卻答錯:

(0.9 - 0)^2 = 0.81

錯誤的代價直接差很多。

這和 AI 系統實際部署時的直覺很接近。

我其實不一定最怕模型說:

我只有 55% 確定。

然後答錯。

更危險的情況通常是:

我 99% 確定。

結果答案卻是錯的。

在今天的 synthetic experiment 裡,實際結果是:

Scenario Accuracy Mean Confidence Gap Brier Score ECE
matched_confidence 0.75 0.75 0.00 0.1650 0.00
overconfident 0.75 0.95 0.20 0.2275 0.20

兩組 Accuracy 一模一樣。

但 Brier Score 從:

0.165

上升到:

0.2275

也就是第二組雖然「答對率完全沒有下降」,它提供的 probability quality 卻明顯變差了。

不過這裡也要特別小心一件事。

Brier Score 不等於純粹的 Calibration Error。

它是一個 probabilistic scoring rule,會同時受到 correctness 與 confidence quality 影響。

所以我不打算把 Brier Score 當成「唯一的校準分數」。

它比較像是今天 evaluator 裡的一個 complementary metric。


ECE:0.8 的信心,真的有接近 80% 嗎?

接下來才是今天最直接針對 Calibration 的指標:

Expected Calibration Error,ECE。

概念其實比名字簡單很多。

我先把 confidence 分成數個區間。

Day 7 暫時使用 5 個 equal-width bins:

[0.0, 0.2)
[0.2, 0.4)
[0.4, 0.6)
[0.6, 0.8)
[0.8, 1.0]

接著對每一個 bin 比較:

平均 confidence

實際 accuracy

兩者差多少。

最後再按照每個 bin 裡面的樣本數加權。

公式可以寫成:

ECE
= Σ (bin_count / N)
  × |empirical_accuracy - mean_confidence|

今天第一組資料會得到:

matched_confidence

[0.0, 0.2)
count = 0

[0.2, 0.4)
count = 0

[0.4, 0.6)
count = 0

[0.6, 0.8)
count = 10
mean confidence = 0.60
empirical accuracy = 0.60
absolute gap = 0.00

[0.8, 1.0]
count = 10
mean confidence = 0.90
empirical accuracy = 0.90
absolute gap = 0.00

所以在這個刻意控制的 synthetic construction 裡,兩個 confidence group 都剛好和 observed accuracy 對上。

因此:

ECE = 0.00

我要特別強調,這不代表:

這是一個現實世界中完美校準的 AI。

它只代表:

在我今天建構的 20 筆 synthetic samples,以及目前這個 5-bin 設定下,觀察到的 group frequency 正好吻合 confidence。

第二組就完全不一樣。

全部 20 筆都塞進最後一個 bin:

overconfident

[0.8, 1.0]
count = 20
mean confidence = 0.95
empirical accuracy = 0.75
absolute gap = 0.20

所以:

ECE = 0.20

這時兩組系統的差異終於很清楚了:

Accuracy
0.75 vs 0.75

但是:

ECE
0.00 vs 0.20

Accuracy 完全看不到的東西,被 Calibration 抓到了。

https://ithelp.ithome.com.tw/upload/images/20260921/20184158N2TbuJgTxz.png

建議顯示兩組 Scenario 的 Accuracy、Mean Confidence、Brier Score 與 ECE。


我把 Reliability Diagram 的資料也先留下來了

正常談 Calibration,通常還會畫 Reliability Diagram。

橫軸放:

Mean Confidence

縱軸放:

Empirical Accuracy

如果 confidence 跟實際頻率對得越好,點就會越接近:

y = x

不過 Day 7 我刻意沒有急著加 matplotlib。

因為目前真正重要的不是「畫一張漂亮圖」,而是先確定底層資料結構正確。

所以 evaluator 現在會先輸出每個 bin 的:

  • lower_bound
  • upper_bound
  • count
  • mean_confidence
  • empirical_accuracy
  • absolute_gap

而且會直接存進 metrics.json

例如 matched scenario 的其中一個 bin 會是類似:

{
  "lower_bound": 0.6,
  "upper_bound": 0.8,
  "count": 10,
  "mean_confidence": 0.6,
  "empirical_accuracy": 0.6,
  "absolute_gap": 0.0
}

這代表未來要做 dashboard、matplotlib、Streamlit 或 case viewer 時,不需要重新計算 calibration。

Visualization 可以只是 artifact 的 consumer。

這也是我現在慢慢在建立的架構原則:

Evaluation 負責算,Artifact 負責記,Reporting 負責顯示。

不要全部寫死在同一支 script 裡。


Day 7 已經不是獨立小程式了

這也是今天和前幾天很不一樣的地方。

Day 1~Day 6 一開始都是一天一支比較獨立的小 evaluator。

但在進 Day 7 以前,我先把它們全部整理成 Foundation v1。

第一次整理完成後,測試有:

23 passed

後來再做一輪 semantic parity review,我才發現一件很有趣的事:

測試全部通過,不代表重構後的定義就真的完全一樣。

像 Day 2 Pairwise Jaccard 到底該使用 raw output 還是 normalized output、Day 3 是否要 lowercase、同一個 question 要用哪一個 expected、Day 5 的 Decision Accuracy 到底是在量「有沒有做對回答/拒答決策」,還是在量「答案內容本身對不對」。

這些差異在原本 demo data 上,不一定會直接讓數字改變。

最後我把這些 semantic drift 補成 regression tests,Foundation v1.1 來到:

30 passed

而今天 Calibration 並不是再新增一支:

day07.py

然後跑完就算了。

而是真的加入目前的專案架構:

src/ai_reliability/metrics/calibration.py

再由既有的 Runner 一起執行。

現在:

airlab run --mode demo --config configs/demo.json

一次就會計算 Day 1 到 Day 7。

而一個 run 仍然只產生同樣四種核心 artifacts:

metadata.json
records.jsonl
metrics.json
gate.json

Day 7 的 40 筆 synthetic records 會一起進入:

records.jsonl

Calibration 結果則會進入:

metrics.json

今天加入 Day 7 後,完整測試數量從 Foundation v1.1 的:

30 passed

增加到:

38 passed
0 failed

而且 Day 1~Day 6 的 regression 結果全部維持不變。

這一點對我來說,甚至比今天算出:

ECE = 0.20

更重要。

因為 AI Engineering 如果每新增一個功能,就不小心把前面的 metric definition 改掉,那最後再多指標也沒有意義。

https://ithelp.ithome.com.tw/upload/images/20260921/20184158mR8nYkGKb0.png


Day 7 也第一次正式走了一次 Review Branch

今天還有一個和 metric 本身無關,但對整個專案很重要的改變。

以前我寫完功能、測試通過後,大多就是直接留下程式。

但現在 GitHub 已經變成這個專案的 source of truth,所以 Day 7 我第一次正式把新功能放到:

day07-calibration-review

這個 branch。

實作完成後先跑:

38 passed

再把 branch push 到 GitHub 做 source-level review。

確認:

  • dataset 沒有被誤寫成真實實驗
  • confidence = 1.0 能正確落在最後一個 bin
  • empty bins 可以安全寫入 JSON
  • ECE 有依照 bin sample count 加權
  • scenario 是分開計算
  • Day 7 records 真的進入 artifact
  • Quality Gate 沒有偷偷加入沒有根據的 threshold
  • Day 1~Day 6 沒有被改壞

確認完成後,才透過 fast-forward 合回 main

最後 Day 7 的 commit 是:

397de45 Day 7: add synthetic calibration evaluation

這對我來說也是專案從「每天寫一支 Python」慢慢變成「真的在維護一個 AI Engineering system」的一個分界點。


為什麼我今天還不把 Calibration 放進 Quality Gate?

目前整個 Demo Pipeline 的 Quality Gate 依然是:

BLOCK

但不是因為 Day 7。

目前 Gate 還是沿用前幾天留下來的兩個主要規則:

  • Format Compliance 必須 100%
  • Unsafe Answer 必須為 0

我今天沒有新增例如:

ECE <= 0.05 → PASS
ECE > 0.05 → BLOCK

因為現在如果這樣做,其實只是亂訂一個看起來很工程化的數字。

今天只有 20 筆 synthetic samples,而且 ECE 本來就會受到很多條件影響:

  • bin 數量
  • bin 邊界
  • 樣本量
  • confidence distribution

我現在沒有足夠的 real evidence 可以說:

ECE 超過多少就一定不能部署。

所以今天 Calibration 先停在:

Measurement

而不是:

Policy

我覺得這個差異非常重要。

Quality Gate 的 threshold 應該來自任務需求、風險容忍度和實際實驗,而不是因為程式裡需要一個數字,就隨便寫一個 0.1。


今天最大的收穫:Confidence 也需要被驗證

做到現在,我對「AI Reliability」的理解又往前推了一層。

一開始最直覺的問題是:

它答對了嗎?

後來發現還要問:

它每次都穩嗎?

再後來是:

不知道的時候,它願意停下來嗎?

Day 6 則變成:

只留下高 confidence 的答案,Risk 會不會下降?

但今天才真正補上下一個問題:

那個 confidence 本身,有資格叫 confidence 嗎?

如果一個系統 Accuracy 75%,每一題卻都聲稱自己有 95% 把握,單看 Accuracy 甚至看不出問題。

這也是今天 controlled experiment 最想證明的事情。

兩個 scenario:

Accuracy A = 0.75
Accuracy B = 0.75

但:

ECE A = 0.00
ECE B = 0.20

Accuracy 沒有變。

改變的是:

系統對自己有多了解。

而我開始覺得,這可能才是「可信任的 AI」很重要的一部分。

不是永遠不能犯錯。

而是它對自己「可能會錯」這件事,究竟有沒有概念。


Day 7 的限制

今天所有 calibration 結果都必須加上一個大前提:

這是 Synthetic Controlled Demo。

0.900.600.95 這些 confidence 都是我刻意建構的數字。

它們不是:

  • 真實 LLM 的 confidence
  • 模型實際輸出的 calibrated probability
  • 某一個模型的可靠度實測結果

所以也不能拿今天的:

ECE = 0.00

或:

ECE = 0.20

去宣稱哪個真實模型比較可靠。

而且目前 ECE 固定示範:

5 equal-width bins

不同 binning strategy、不同 sample size,最後數值都可能改變。

今天真正完成的是:

Calibration evaluator 本身的第一個可驗證版本。

還不是:

某個真實 AI 模型已經通過 Calibration Test。

這兩件事情我會繼續分得很清楚。


下一步:LLM 的 Confidence 到底從哪裡來?

Day 7 把「校準的尺」先做出來了。

下一個問題就變得更麻煩:

LLM 的 confidence 到底要從哪裡來?

最直覺的方法可能是直接問模型:

請告訴我你有幾 % 把握。

但模型自己說:

95%

真的能直接當成 probability 嗎?

還是應該從:

  • 多次採樣的一致程度
  • 模型輸出的 log probability
  • 外部 verifier
  • answer agreement
  • 其他 uncertainty signal

去估計?

如果 confidence 的來源本身沒有意義,那後面再精密的 Calibration evaluator 也救不了它。

所以 Day 7 我先把尺做出來。

接下來,才是真正拿 AI 來量。


上一篇
#Day 6|AI 回答得越多,真的越好嗎?第一次做 Risk-Coverage Curve
下一篇
Day 8|AI 說「我有 100% 把握」能信嗎?第一次跑真正的 LLM Confidence Experiment
系列文
AI Reliability Lab:30 天用 Python 把「AI 好像很準」變成可以量的工程指標10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言